<?php
if (function_exists("dprofiler_disable"))
    dprofiler_disable();
error_reporting(E_ALL & ~E_NOTICE);

if (get_magic_quotes_gpc()){
	isset($_GET['file']) && $_GET['file'] = stripslashes($_GET['file']);
}
if (empty($_GET['file'])){
	print_input();
	print_footer();
}else if (!file_exists($_GET['file'])){
	print_input('文件不存在');
	print_footer();
}

$dprofiler_stat = @unserialize(file_get_contents($_GET['file']));
if (!is_array($dprofiler_stat)){
	print_input('解析错误！');
	print_footer();
}

array_sum_wt($dprofiler_stat);

print_input();
print_cmd();

switch ($_GET['type']){
	case 1:// 绘图
		print_img('main()', $dprofiler_stat, 1);
		break;
	case 2:
	default:
		print_sort();
		break;
}

/**
 * 输出函数调用时间排名
 *
 */
function print_sort()
{
	global $dprofiler_stat;
	$arr_list = array();
	
	$arr_list['main()'] = $dprofiler_stat;
	unset($arr_list['main()']['stacks']);
	
	func_sort($dprofiler_stat['stacks'], $arr_list);
	
	$sortby = $_GET['s'];
	if (!in_array($sortby, array("wt", "iwt", "swt", "count", "mu", "mpu")))
		$sortby = 'wt';
	
	// 取得列的列表
	foreach ($arr_list as $key => $row) {
	    $volume[$key]  = $row[$sortby];
	}
	
	array_multisort($volume, SORT_DESC, $arr_list);

	$param = 'file=' . urlencode($_GET['file']) . '&type=2&s=';
	echo "<table class=\"tableA\"><tr>
	<th>函数名(前20个)</th>
	<th><a href=\"?{$param}wt\">总时间wt</a></th>
	<th><a href=\"?{$param}iwt\">子函数总时间iwt</th>
	<th><a href=\"?{$param}swt\">自身执行时间swt</th>
	<th><a href=\"?{$param}count\">被调用次数</th>
	<th><a href=\"?{$param}mu\">内存差值mu</th>
	<th><a href=\"?{$param}mpu\">内存峰值差值mpu</th>
	</tr>
";
	$i = 0;
	foreach ($arr_list as $func => $v){
		if ($i == 20)break;
		
		$v['wt'] = sprintf("%.3fs", $v['wt']);
		$v['iwt'] = sprintf("%.3fs", $v['iwt']);
		$v['swt'] = sprintf("%.3fs", $v['swt']);
		$title = "";
		if (strpos($func, "::") !== false){
			$arr = explode("::", $func, 2);
			$title = addslashes($arr[1]);
			$func = $arr[0] . "::" . pathinfo($arr[1], PATHINFO_BASENAME);
		}
		$v['mu'] = get_size($v['mu']);
		$v['mpu'] = get_size($v['mpu']);
		echo "<tr>
	<td width=300><span title=\"{$title}\">{$func}</span></td>
	<td>{$v['wt']}</td>
	<td>{$v['iwt']}</td>
	<td>{$v['swt']}</td>
	<td>{$v['count']}</td>
	<td>{$v['mu']}</td>
	<td>{$v['mpu']}</td>
	</tr>
";
		$i++;
	}
	
	echo "</table>";
}

function print_img($func, $stats, $type)
{	
	$max_func = "";
	$sec_func = "";
	if ($type){
		$arr_sort = array();
		foreach ($stats['stacks'] as $sfunc => $v)
			$arr_sort[$sfunc] = $v['wt'];
		arsort($arr_sort);
		$max_func = key($arr_sort);next($arr_sort);
		$sec_func = key($arr_sort);
	}
	
	if ($func == 'main()'){
		echo '<div>';
	}else{
		if ($type)
			echo '<div style="padding-left:35px;display:">';
		else 
			echo '<div style="padding-left:35px;display:none">';
	}
	
	
	foreach ($stats['stacks'] as $tfunc => $v){		
		if (strpos($tfunc, "::") !== false){
			$arr = explode("::", $tfunc, 2);
			$sfunc = $arr[0] . "::" . pathinfo($arr[1], PATHINFO_BASENAME);
		}
		
		$str =  $sfunc . $stack_level .' wt:' . sprintf("%.3fs", $v['wt']) . ' swt:' . sprintf("%.3fs", $v['swt']);		
		$plus = (isset($v['stacks']) && !empty($v['stacks']))?'+':"";
		
		$max_style = "";
		if ($max_func == $tfunc){
			$ttype = 1;
			if ($type == 1)
				$max_style = 'style="color:#FF0000;"';
			else{
				$max_style = 'style="color:#FFA500;"';
				$ttype = 2;
			}
			if (!empty($plus)) $plus = '-';
		}else if ($func == 'main()' && $sec_func == $tfunc){
			$ttype = 2;
			$max_style = 'style="color:#FFA500;"';
			if (!empty($plus)) $plus = '-';
		}else
			$ttype = 0;
		
		echo '<div><span>' . $plus . '</span><div class="divfunc" ' . $max_style . ' onclick="javascript:return toggle(this.parentNode);">' . $str . '</div>';
		
		if (isset($v['stacks']) && !empty($v['stacks']))
			print_img($sfunc, $v, $ttype);
		
		echo '</div>';
	}
	echo '</div>';
}

/**
 * 处理所有的函数调用
 *
 * @param Array $stat
 * @param Array $arr_list
 */
function func_sort($stat, &$arr_list)
{
	reset($stat);
	while(list($func, $v) = each($stat)){
		if (isset($arr_list[$func])){
			$arr_list[$func]['count'] += $v['count'];
			$arr_list[$func]['mu'] += $v['mu'];
			$arr_list[$func]['mpu'] += $v['mpu'];
			$arr_list[$func]['wt'] += $v['wt'];
		}else{
			$arr_list[$func] = $v;
			unset($arr_list[$func]['stacks']);
		}
		if (isset($v['stacks']) && !empty($v['stacks'])){
			func_sort($v['stacks'], $arr_list);
		}
	}
}


function array_sum_wt(&$stat)
{
	$t = 0;
	foreach ($stat['stacks'] as &$v){
		$t += $v['wt'];
		
		if (isset($v['stacks']) && !empty($v['stacks']))
			array_sum_wt($v);
	}
	$stat['iwt'] = $t;
	$stat['swt'] = $stat['wt'] - $t;
}

/**
 * 输出输入框
 *
 * @param string $str_err
 */
function print_input( $str_err = "")
{
	print_header();
echo <<<EOT
<form>
文件地址：<input type="text" name="file" value="{$_GET['file']}" size="150"/>
<input type="submit" name="submit" value="提交" />
</form>
EOT;
	if (!empty($str_err)){
		echo "<font color=\"red\">{$str_err}</font>";
	}
}

function print_cmd()
{
	global $dprofiler_stat;
	$file = urlencode($_GET['file']);
	
	// 读取目录文件
	$dir = pathinfo($_GET['file'], PATHINFO_DIRNAME);
	$filename = pathinfo($_GET['file'], PATHINFO_BASENAME);
	$arr_files = scandir($dir);
	$arr_stat_files = array();
	foreach ($arr_files as $v){
		if (is_file($dir . DIRECTORY_SEPARATOR . $v)){
			$arr_stat_files[$v] = filemtime($dir . DIRECTORY_SEPARATOR  . $v);
		}
	}
	
	$prev_key = "";
	$next_key = "";
	asort($arr_stat_files);
	reset($arr_stat_files);
	$flag = false;
	while(list($key, $v) = each($arr_stat_files)){
		if ($key == $filename){
			$flag = true;
			break;
		}
		$prev_key = $key;
	}
	if ($flag){
		list($next_key, ) = each($arr_stat_files);
	}
	
	$str_prev = '"#prev" title="没有了"';
	$str_next = '"#next" title="没有了"';
	if ($flag && !empty($prev_key)){
		$str_prev = "\"?type={$_GET['type']}&file=" . urlencode($dir . DIRECTORY_SEPARATOR . $prev_key) . '" title="' . addslashes($prev_key) . '"';
	}
	if ($flag && !empty($next_key)){
		$str_next = "\"?type={$_GET['type']}&file=" . urlencode($dir . DIRECTORY_SEPARATOR . $next_key) . '" title="' . addslashes($next_key) . '"';
	}
	
	echo '<p>执行总时间：' . sprintf("%.3f", $dprofiler_stat['wt']) . 's <a href="?type=2&file=' . $file . '">函数调用排行</a> <a href="?type=1&file=' . $file . '">调用堆栈</a> <a href=' . $str_prev . '>上一个</a> <a href=' . $str_next . '>下一个</a> </p>';
}

/**
 * 输出头部
 *
 */
function print_header()
{
	header("Content-type: text/html; charset=utf-8");
echo <<<EOT
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=7" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>DPROFILER</title>
</head>
<style>
body{margin:0}
.tableA {border:#BBBBBB solid 1px;border-collapse:collapse;}
.tableA th{background-color:#CCCCCC;border-right:#BBBBBB solid 2px;}
.tableA td{border-right:#BBBBBB solid 1px;border-bottom:#BBBBBB solid 1px;padding:3px 15px 1px 15px;font: 12px Arial,宋体;color:#272727; background-color:#FFFFFF;word-break: keep-all;white-space:nowrap;}
a{color:#CC0000;text-decoration: underline;}
a:link, a:active, a:hover{color:#CC0000;text-decoration: underline;}
a:visited{color:#AA0000;	text-decoration: none;}
p{margin:0}
.divfunc{background:#F8F8FF;min-width:100px;width:100px; height:20px;margin:0px;display:inline;}
</style>
<script>
function toggle(obj)
{
	if (obj.childNodes.length > 2){
		if (obj.childNodes[2].style.display == 'none'){	
			obj.childNodes[0].innerHTML = '-';
			obj.childNodes[2].style.display = '';
		}else{
			obj.childNodes[0].innerHTML = '+';
			obj.childNodes[2].style.display = 'none';
		}
	}
}
</script>
<body>
EOT;
}

function print_footer()
{
	echo '</body></html>';
exit;
}

function get_size($size)
{
	if ($size < 1024){
		return $size . 'B';
	}else if ($size < 1024 * 1024){
		return sprintf("%.3fKB", $size / 1024);
	}else if ($size < 1024 * 1024 * 1024){
		return sprintf("%.3fMB", $size / (1024 * 1024));
	}else if ($size < 1024 * 1024 * 1024 * 1024){
		return sprintf("%.3fGB", $size / (1024 * 1024 * 1024 * 1024));
	}
}
